﻿using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.Cryptography;

namespace MINERP.COM.DBHelper {
	/// <summary>The data protector.</summary>
	public unsafe class DataProtector {
		/// <summary>The cryptprotec t_ loca l_ machine.</summary>
		private const int CRYPTPROTECT_LOCAL_MACHINE = 4;
		/// <summary>The cryptprotec t_ u i_ forbidden.</summary>
		private const int CRYPTPROTECT_UI_FORBIDDEN = 1;
		/// <summary>The arr desiv.</summary>
		private static readonly byte[] arrDESIV = {
			                                          0x37,
			                                          0x67,
			                                          0xf6,
			                                          0x4f,
			                                          0x24,
			                                          0x63,
			                                          0xa7,
			                                          3
		                                          };
		/// <summary>The arr des key.</summary>
		private static readonly byte[] arrDESKey = {
			                                           0x2a,
			                                           0x10,
			                                           0x5d,
			                                           0x9c,
			                                           0x4e,
			                                           4,
			                                           0xda,
			                                           0x20
		                                           };
		/// <summary>The null ptr.</summary>
		private static readonly IntPtr NullPtr = IntPtr.Zero;
		/// <summary>The store.</summary>
		private readonly Store store;
		/// <summary>Initializes a new instance of the <see cref="DataProtector" /> class.</summary>
		/// <param name="tempStore">The temp store.</param>
		public DataProtector(Store tempStore) {
			store = tempStore;
		}
		/// <summary>The crypt protect data.</summary>
		/// <param name="pDataIn">The p data in.</param>
		/// <param name="szDataDescr">The sz data descr.</param>
		/// <param name="pOptionalEntropy">The p optional entropy.</param>
		/// <param name="pvReserved">The pv reserved.</param>
		/// <param name="pPromptStruct">The p prompt struct.</param>
		/// <param name="dwFlags">The dw flags.</param>
		/// <param name="pDataOut">The p data out.</param>
		/// <returns>The crypt protect data.</returns>
		[DllImport("Crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
		private static extern bool CryptProtectData(ref DATA_BLOB pDataIn, string szDataDescr, ref DATA_BLOB pOptionalEntropy, IntPtr pvReserved, ref CRYPTPROTECT_PROMPTSTRUCT pPromptStruct, int dwFlags, ref DATA_BLOB pDataOut);
		/// <summary>The crypt unprotect data.</summary>
		/// <param name="pDataIn">The p data in.</param>
		/// <param name="szDataDescr">The sz data descr.</param>
		/// <param name="pOptionalEntropy">The p optional entropy.</param>
		/// <param name="pvReserved">The pv reserved.</param>
		/// <param name="pPromptStruct">The p prompt struct.</param>
		/// <param name="dwFlags">The dw flags.</param>
		/// <param name="pDataOut">The p data out.</param>
		/// <returns>The crypt unprotect data.</returns>
		[DllImport("Crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
		private static extern bool CryptUnprotectData(ref DATA_BLOB pDataIn, string szDataDescr, ref DATA_BLOB pOptionalEntropy, IntPtr pvReserved, ref CRYPTPROTECT_PROMPTSTRUCT pPromptStruct, int dwFlags, ref DATA_BLOB pDataOut);
		/// <summary>The decode.</summary>
		/// <param name="m_Need_Encode_String">The m_ need_ encode_ string.</param>
		/// <returns>The decode.</returns>
		/// <exception cref="Exception"></exception>
		public static string Decode(string m_Need_Encode_String) {
			try {
				if (m_Need_Encode_String == null) {
					throw new Exception("Error: \n源字符串为空！！");
				}
				DESCryptoServiceProvider provider = new DESCryptoServiceProvider();
				MemoryStream stream = new MemoryStream(Convert.FromBase64String(m_Need_Encode_String));
				CryptoStream stream2 = new CryptoStream(stream, provider.CreateDecryptor(arrDESKey, arrDESIV), CryptoStreamMode.Read);
				StreamReader reader = new StreamReader(stream2);
				return reader.ReadToEnd();
			}
			catch {
				return string.Empty;
			}
		}
		/// <summary>The decrypt.</summary>
		/// <param name="cipherText">The cipher text.</param>
		/// <param name="optionalEntropy">The optional entropy.</param>
		/// <returns></returns>
		/// <exception cref="Exception"></exception>
		public byte[] Decrypt(byte[] cipherText, byte[] optionalEntropy) {
			Exception exception;
			DATA_BLOB pDataOut = new DATA_BLOB();
			DATA_BLOB pDataIn = new DATA_BLOB();
			CRYPTPROTECT_PROMPTSTRUCT ps = new CRYPTPROTECT_PROMPTSTRUCT();
			InitPromptstruct(ref ps);
			try {
				int num2;
				try {
					int length = cipherText.Length;
					pDataIn.pbData = Marshal.AllocHGlobal(length);
					if (IntPtr.Zero == pDataIn.pbData) {
						throw new Exception("Unable to allocate cipherText buffer.");
					}
					pDataIn.cbData = length;
					Marshal.Copy(cipherText, 0, pDataIn.pbData, pDataIn.cbData);
				}
				catch (Exception exception1) {
					exception = exception1;
					throw new Exception("Exception marshalling data. " + exception.Message);
				}
				DATA_BLOB pOptionalEntropy = new DATA_BLOB();
				if (Store.Machine == store) {
					num2 = 5;
					if (null == optionalEntropy) {
						optionalEntropy = new byte[0];
					}
					try {
						int cb = optionalEntropy.Length;
						pOptionalEntropy.pbData = Marshal.AllocHGlobal(cb);
						if (IntPtr.Zero == pOptionalEntropy.pbData) {
							throw new Exception("Unable to allocate entropy buffer.");
						}
						pOptionalEntropy.cbData = cb;
						Marshal.Copy(optionalEntropy, 0, pOptionalEntropy.pbData, cb);
					}
					catch (Exception exception2) {
						exception = exception2;
						throw new Exception("Exception entropy marshalling data. " + exception.Message);
					}
				}
				else {
					num2 = 1;
				}
				if (!CryptUnprotectData(ref pDataIn, null, ref pOptionalEntropy, IntPtr.Zero, ref ps, num2, ref pDataOut)) {
					throw new Exception("Decryption failed. " + GetErrorMessage(Marshal.GetLastWin32Error()));
				}
				if (IntPtr.Zero != pDataIn.pbData) {
					Marshal.FreeHGlobal(pDataIn.pbData);
				}
				if (IntPtr.Zero != pOptionalEntropy.pbData) {
					Marshal.FreeHGlobal(pOptionalEntropy.pbData);
				}
			}
			catch (Exception exception3) {
				exception = exception3;
				throw new Exception("Exception decrypting. " + exception.Message);
			}
			byte[] destination = new byte[pDataOut.cbData];
			Marshal.Copy(pDataOut.pbData, destination, 0, pDataOut.cbData);
			return destination;
		}
		/// <summary>The encode.</summary>
		/// <param name="m_Need_Encode_String">The m_ need_ encode_ string.</param>
		/// <returns>The encode.</returns>
		/// <exception cref="Exception"></exception>
		public static string Encode(string m_Need_Encode_String) {
			if (m_Need_Encode_String == null) {
				throw new Exception("Error: \n源字符串为空！！");
			}
			DESCryptoServiceProvider provider = new DESCryptoServiceProvider();
			MemoryStream stream = new MemoryStream();
			CryptoStream stream2 = new CryptoStream(stream, provider.CreateEncryptor(arrDESKey, arrDESIV), CryptoStreamMode.Write);
			StreamWriter writer = new StreamWriter(stream2);
			writer.Write(m_Need_Encode_String);
			writer.Flush();
			stream2.FlushFinalBlock();
			stream.Flush();
			return Convert.ToBase64String(stream.GetBuffer(), 0, (int) stream.Length);
		}
		/// <summary>The encrypt.</summary>
		/// <param name="plainText">The plain text.</param>
		/// <param name="optionalEntropy">The optional entropy.</param>
		/// <returns></returns>
		/// <exception cref="Exception"></exception>
		public byte[] Encrypt(byte[] plainText, byte[] optionalEntropy) {
			Exception exception;
			DATA_BLOB pDataIn = new DATA_BLOB();
			DATA_BLOB pDataOut = new DATA_BLOB();
			DATA_BLOB pOptionalEntropy = new DATA_BLOB();
			CRYPTPROTECT_PROMPTSTRUCT ps = new CRYPTPROTECT_PROMPTSTRUCT();
			InitPromptstruct(ref ps);
			try {
				int num;
				int length;
				try {
					length = plainText.Length;
					pDataIn.pbData = Marshal.AllocHGlobal(length);
					if (IntPtr.Zero == pDataIn.pbData) {
						throw new Exception("Unable to allocate plaintext buffer.");
					}
					pDataIn.cbData = length;
					Marshal.Copy(plainText, 0, pDataIn.pbData, length);
				}
				catch (Exception exception1) {
					exception = exception1;
					throw new Exception("Exception marshalling data. " + exception.Message);
				}
				if (Store.Machine == store) {
					num = 5;
					if (null == optionalEntropy) {
						optionalEntropy = new byte[0];
					}
					try {
						length = optionalEntropy.Length;
						pOptionalEntropy.pbData = Marshal.AllocHGlobal(optionalEntropy.Length);
						if (IntPtr.Zero == pOptionalEntropy.pbData) {
							throw new Exception("Unable to allocate entropy data buffer.");
						}
						Marshal.Copy(optionalEntropy, 0, pOptionalEntropy.pbData, length);
						pOptionalEntropy.cbData = length;
					}
					catch (Exception exception2) {
						exception = exception2;
						throw new Exception("Exception entropy marshalling data. " + exception.Message);
					}
				}
				else {
					num = 1;
				}
				if (!CryptProtectData(ref pDataIn, string.Empty, ref pOptionalEntropy, IntPtr.Zero, ref ps, num, ref pDataOut)) {
					throw new Exception("Encryption failed. " + GetErrorMessage(Marshal.GetLastWin32Error()));
				}
			}
			catch (Exception exception3) {
				exception = exception3;
				throw new Exception("Exception encrypting. " + exception.Message);
			}
			byte[] destination = new byte[pDataOut.cbData];
			Marshal.Copy(pDataOut.pbData, destination, 0, pDataOut.cbData);
			return destination;
		}
		/// <summary>The format message.</summary>
		/// <param name="dwFlags">The dw flags.</param>
		/// <param name="lpSource">The lp source.</param>
		/// <param name="dwMessageId">The dw message id.</param>
		/// <param name="dwLanguageId">The dw language id.</param>
		/// <param name="lpBuffer">The lp buffer.</param>
		/// <param name="nSize">The n size.</param>
		/// <param name="Arguments">The arguments.</param>
		/// <returns>The format message.</returns>
		[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
		private static extern int FormatMessage(int dwFlags, ref IntPtr lpSource, int dwMessageId, int dwLanguageId, ref string lpBuffer, int nSize, IntPtr* Arguments);
		/// <summary>The get error message.</summary>
		/// <param name="errorCode">The error code.</param>
		/// <returns>The get error message.</returns>
		/// <exception cref="Exception"></exception>
		private static string GetErrorMessage(int errorCode) {
			int num = 0x100;
			int num2 = 0x200;
			int num3 = 0x1000;
			int nSize = 0xff;
			string lpBuffer = string.Empty;
			int dwFlags = (num | num3) | num2;
			IntPtr lpSource = new IntPtr();
			IntPtr arguments = new IntPtr();
			int num6 = FormatMessage(dwFlags, ref lpSource, errorCode, 0, ref lpBuffer, nSize, &arguments);
			if (0 == num6) {
				throw new Exception("Failed to format message for error code " + errorCode + ". ");
			}
			return lpBuffer;
		}
		/// <summary>The init promptstruct.</summary>
		/// <param name="ps">The ps.</param>
		private void InitPromptstruct(ref CRYPTPROTECT_PROMPTSTRUCT ps) {
			ps.cbSize = Marshal.SizeOf(typeof (CRYPTPROTECT_PROMPTSTRUCT));
			ps.dwPromptFlags = 0;
			ps.hwndApp = NullPtr;
			ps.szPrompt = null;
		}

		#region Nested type: CRYPTPROTECT_PROMPTSTRUCT

		/// <summary>The cryptprotec t_ promptstruct.</summary>
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
		internal struct CRYPTPROTECT_PROMPTSTRUCT {
			/// <summary>The cb size.</summary>
			public int cbSize;
			/// <summary>The dw prompt flags.</summary>
			public int dwPromptFlags;
			/// <summary>The hwnd app.</summary>
			public IntPtr hwndApp;
			/// <summary>The sz prompt.</summary>
			public string szPrompt;
		}

		#endregion

		#region Nested type: DATA_BLOB

		/// <summary>The dat a_ blob.</summary>
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
		internal struct DATA_BLOB {
			/// <summary>The cb data.</summary>
			public int cbData;
			/// <summary>The pb data.</summary>
			public IntPtr pbData;
		}

		#endregion

		// Nested Types
	}
}
